package state

import (
	//"fmt"
	"osiris/config"
	"osiris/core/conversion"
	"osiris/core/routine"
	"osiris/dto"
	"osiris/logger"
	"osiris/ocrypto/ecdsa"
)

// PledgeTxHandler 代币质押交易
type PledgeTxHandler struct {
	TxData dto.TxData
}

func (txHandler PledgeTxHandler) Verify(tries ...interface{}) bool {
	tempAccountTrie, ok1 := tries[0].(*AccountStateTrie)
	if !ok1 {
		logger.Warn(map[string]interface{}{"[state] [Verify Pledge TX]": "unknown account trie!"})
		return false
	}
	tempPeerTrie, ok2 := tries[1].(*PeerStateTrie)
	if !ok2 {
		logger.Warn(map[string]interface{}{"[state] [Verify Pledge TX]": "unknown peer trie!"})
		return false
	}

	//检查来源账户地址是否存在
	fromLeaf, fromExist := tempAccountTrie.GetLeaf(ecdsa.StrToAccountBytes(txHandler.TxData.FromAddr))
	if !fromExist {
		logger.Warn(map[string]interface{}{"[state] [Verify Pledge TX]": "source account addr does not exist!"})
		return false
	}

	//检查来源账户的余额是否足够
	if fromLeaf.Asset < txHandler.TxData.Amount {
		logger.Warn(map[string]interface{}{"[state] [Verify Pledge TX]": "source account addr does not have enough asset!"})
		return false
	}

	//检查目的节点是否存在
	peerIDBytes, err := conversion.StrToPeerIDBytes(txHandler.TxData.ToAddr)
	if err != nil {
		logger.Error(map[string]interface{}{"[state] [Verify Pledge Tx] core.StrToPeerIDByte()": err})
		return false
	}
	toLeaf, toExist := tempPeerTrie.GetLeaf(peerIDBytes)
	if !toExist {
		logger.Warn(map[string]interface{}{"[state] [Verify Pledge TX]": "destination peer ID does not exist!"})
		return false
	}

	//检查目的节点是否在冷却
	if toLeaf.CoolDown {
		logger.Warn(map[string]interface{}{"[state] [Verify Pledge TX]": "destination peer ID is cooled down!"})
		return false
	}

	//检查来源账户nonce是否合法
	if fromLeaf.Nonce == txHandler.TxData.Nonce {
		return true
	}

	logger.Warn(map[string]interface{}{"[state] [Verify Pledge TX]": "nonce does not match!"})
	return false
}

func (txHandler PledgeTxHandler) Commit(tries ...interface{}) bool {
	tempAccountTrie, ok1 := tries[0].(*AccountStateTrie)
	if !ok1 {
		logger.Error(map[string]interface{}{"[state] [Verify Pledge TX]": "unknown account trie!"})
		return false
	}
	tempPeerTrie, ok2 := tries[1].(*PeerStateTrie)
	if !ok2 {
		logger.Error(map[string]interface{}{"[state] [Verify Pledge TX]": "unknown peer trie!"})
		return false
	}

	//修改来源账户状态：扣金额、nonce+1
	fromAccountAddrBytes := ecdsa.StrToAccountBytes(txHandler.TxData.FromAddr)
	fromLeaf, fromExist := tempAccountTrie.GetLeaf(fromAccountAddrBytes)
	if !fromExist {
		logger.Error(map[string]interface{}{"[state] [Commit Pledge TX]": "source account addr does not exist!"})
		return false
	}
	fromLeaf.CommitAssetChange(-txHandler.TxData.Amount, txHandler.TxData.CoinSince)
	//logger.Debug(map[string]interface{}{"[state] [Commit Transform TX]": fmt.Sprintf("hash: %s,  fromAddr: %s,  amount: %d, current: %d", txHandler.TxData.TxHash, txHandler.TxData.FromAddr, txHandler.TxData.Amount, fromLeaf.Asset)})

	//如果nonce达到了配置里的最大nonce值，从0开始（为了区别账户创建时的最小随机数1），否则+1
	if fromLeaf.Nonce == config.MaxAccountNonce.Int64() {
		fromLeaf.Nonce = 0
	} else {
		fromLeaf.Nonce += 1
	}

	//修改目的节点状态：加金额
	peerIDBytes, err := conversion.StrToPeerIDBytes(txHandler.TxData.ToAddr)
	if err != nil {
		logger.Error(map[string]interface{}{"[state] [Commit Pledge Tx] core.StrToPeerIDByte()": err})
		return false
	}
	toLeaf, toExist := tempPeerTrie.GetLeaf(peerIDBytes)
	if !toExist {
		logger.Error(map[string]interface{}{"[state] [Commit Pledge TX]": "destination peer does not exist!"})
		return false
	}
	toLeaf.CommitAssetChange(txHandler.TxData.Amount, txHandler.TxData.CoinSince)
	//logger.Debug(map[string]interface{}{"[state] [Commit Transform TX]": fmt.Sprintf("hash: %s,  toAddr: %s,  amount: %d, current: %d", txHandler.TxData.TxHash, txHandler.TxData.ToAddr, txHandler.TxData.Amount, toLeaf.Asset)})

	batch := routine.AtomicRoutineBatch{}
	return batch.Add(&AccountCommitRoutine{
		Kvs: []StateKeyValue{{
			Key:  fromAccountAddrBytes,
			Leaf: fromLeaf,
		}},
		Trie: tempAccountTrie,
	}).Add(&PeerCommitRoutine{
		Kvs: []StateKeyValue{{
			Key:  peerIDBytes,
			Leaf: toLeaf,
		}},
		Trie: tempPeerTrie,
	}).Execute()
}

func (txHandler PledgeTxHandler) Undo(tries ...interface{}) bool {
	tempAccountTrie, ok1 := tries[0].(*AccountStateTrie)
	if !ok1 {
		logger.Error(map[string]interface{}{"[state] [Undo Pledge TX]": "unknown account trie!"})
		return false
	}
	tempPeerTrie, ok2 := tries[1].(*PeerStateTrie)
	if !ok2 {
		logger.Error(map[string]interface{}{"[state] [Undo Pledge TX]": "unknown peer trie!"})
		return false
	}

	//修改来源账户状态：加金额、nonce-1
	fromAccountAddrBytes := ecdsa.StrToAccountBytes(txHandler.TxData.FromAddr)
	fromLeaf, fromExist := tempAccountTrie.GetLeaf(fromAccountAddrBytes)
	if !fromExist {
		logger.Error(map[string]interface{}{"[state] [Undo Pledge TX]": "source account addr does not exist!"})
		return false
	}
	fromLeaf.UndoAssetChange(-txHandler.TxData.Amount, txHandler.TxData.CoinSince)
	if fromLeaf.Nonce == 0 {
		fromLeaf.Nonce = config.MaxAccountNonce.Int64()
	} else {
		fromLeaf.Nonce -= 1
	}

	//修改目的节点状态：减金额
	peerIDBytes, err := conversion.StrToPeerIDBytes(txHandler.TxData.ToAddr)
	if err != nil {
		logger.Error(map[string]interface{}{"[state] [Commit Pledge Tx] core.StrToPeerIDByte()": err})
		return false
	}
	toLeaf, toExist := tempPeerTrie.GetLeaf(peerIDBytes)
	if !toExist {
		logger.Error(map[string]interface{}{"[state] [Commit Pledge TX]": "destination peer does not exist!"})
		return false
	}
	toLeaf.UndoAssetChange(-txHandler.TxData.Amount, txHandler.TxData.CoinSince)

	batch := routine.AtomicRoutineBatch{}
	return batch.Add(&AccountCommitRoutine{
		Kvs: []StateKeyValue{{
			Key:  fromAccountAddrBytes,
			Leaf: fromLeaf,
		}},
		Trie: tempAccountTrie,
	}).Add(&PeerCommitRoutine{
		Kvs: []StateKeyValue{{
			Key:  peerIDBytes,
			Leaf: toLeaf,
		}},
		Trie: tempPeerTrie,
	}).Execute()
}
